package com.minelx.sqlstructures.core;

import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;
import java.util.stream.IntStream;

import static java.util.stream.Collectors.toList;

public class ResultColumns {

	private final ResultSetMetaData metaData;

	private final List<Column> columns;

	private final ColumnType[] columnTypes;

	private final List<String> columnLabels;

	public ResultColumns(ResultSetMetaData metaData) {
		this.metaData = metaData;
		int columnCounts = columnCounts(metaData);
		// fetching type of columns
		columnTypes = IntStream.rangeClosed(1, columnCounts)
				.map(this::queryColumnType)
				.mapToObj(ColumnType::from)
				.toArray(ColumnType[]::new);
		columnLabels = IntStream.rangeClosed(1, columnCounts)
				.mapToObj(this::queryColumnLabel)
				.collect(toList());
		columns = IntStream.range(0, columnCounts)
				.mapToObj(this::createColumn)
				.collect(toList());
	}

	List<Column> columns() {
		return columns;
	}

	List<String> labels() {
		return columnLabels;
	}

	String queryColumnLabel(int index) {
		try {
			return metaData.getColumnLabel(index);
		} catch (SQLException e) {
			throw new RuntimeException("error while getting column label at: " + index, e);
		}
	}

	int queryColumnType(int index) {
		try {
			return metaData.getColumnType(index);
		} catch (SQLException e) {
			throw new RuntimeException("error while getting column type at: " + index, e);
		}
	}

	private Column createColumn(int columnIndex) {
		return new Column(columnIndex, columnTypes[columnIndex], columnLabels.get(columnIndex));
	}

	private static int columnCounts(ResultSetMetaData metaData) {
		try {
			return metaData.getColumnCount();
		} catch (SQLException e) {
			throw new RuntimeException("error while fetching meta data.", e);
		}
	}
}
